//
//  TrajectoryCorrectionManager.m
//  YueYueSpecailCarDriver
//
//  Created by 段LL on 17/3/28.
//  Copyright © 2017年 段LL. All rights reserved.
//

#import "TrajectoryCorrectionManager.h"
#import <AMapFoundationKit/AMapFoundationKit.h>
#import <MAMapKit/MAMapKit.h>
#import <MAMapKit/MATraceManager.h>
#import "MapGeometryCalculationManager.h"
#import <QXDataManager/QXDataManager.h>

#import "MapManager.h"

@interface TrajectoryCorrectionManager ()

/// 记录司机行驶过的位置点的集合
@property(nonatomic , strong) NSMutableArray *routeCoordinates;
/// 缓存正在轨迹纠偏时,传过来的点与上一点距离的和的累加
@property(nonatomic , assign) double tempDistance;
/// 记录行驶过的米数,也就是我们需要上传到服务端的目前行驶总距离
@property(nonatomic , assign) double drivingDistance;
/// 订单 uuid
@property(nonatomic , copy) NSString *orderId;
/// 是否需要轨迹纠偏,默认是,如果正在轨迹纠偏计算,那么设为 NO, 如果这次计算失败,设为YES, 那么我们会不管其他条件,获取到新的位置点就会立马进行轨迹纠偏计算
@property(nonatomic , assign) BOOL isLost;
/// 是否计算中
@property(nonatomic , assign) BOOL isProgressing;
/// 轨迹纠偏进程
@property(nonatomic , strong) NSOperation *operation;
/// 最近的距离 单位: 米
@property(nonatomic , assign) double lastedDistance;

@property (nonatomic , assign) MapType currentMapType;

@end

/// [NSString stringWithFormat:@"%@_%@" , self.orderId , DrivingInfo], 存储该订单相关位置信息的 key , 这里的对应的 value 是一个字典格式@{@"DrivingDistance" : @(距离)};      父集
static NSString *DrivingInfoKey = @"DrivingInfoKey";
/// 该订单本地存储的司机行驶距离    一级子集
static NSString *DrivingDistanceKey = @"DrivingDistanceKey";
/// 该订单本地存储的司机行驶过程的位置集合    一级子集
static NSString *RouteCoordinatesKey = @"RouteCoordinatesKey";
/// 该订单本地存储的司机行驶过程的位置集合中位置点的经度    二级子集
static NSString *LatitudeKey = @"LatitudeKey";
/// 该订单本地存储的司机行驶过程的位置集合中位置点的纬度    二级子集
static NSString *LongitudeKey = @"LongitudeKey";

@implementation TrajectoryCorrectionManager
- (NSMutableArray *)routeCoordinates {
    if (!_routeCoordinates) {
        self.routeCoordinates = [NSMutableArray array];
    }
    return _routeCoordinates;
}


// 这里初始化,并从本地获取到存储的信息,并添加到缓存
+ (TrajectoryCorrectionManager *)initWithOrderID:(NSString *)orderId {
    
    TrajectoryCorrectionManager *manager = [TrajectoryCorrectionManager new];
    
    if (orderId == nil) {
        
        return manager;
    }
    
    manager.currentMapType = [MapManager shareManager].currentMapType;

    manager.orderId = orderId;
    manager.drivingDistance = 0.0;
    manager.lastedDistance = 0.0;
    manager.tempDistance = 0.0;
    manager.isLost = YES;
    [manager.routeCoordinates removeAllObjects];

    NSData *jsonData = [[NSUserDefaults standardUserDefaults] valueForKey:[NSString stringWithFormat:@"%@_%@" , manager.orderId , DrivingInfoKey]];
    NSMutableDictionary *drivingInfo = [NSMutableDictionary dictionary];
    if (jsonData) {
        
        [drivingInfo setValuesForKeysWithDictionary:[NSJSONSerialization JSONObjectWithData:jsonData options:(NSJSONReadingAllowFragments) error:nil]];
    }
    
    if (drivingInfo && drivingInfo.allKeys.count > 0) { // 如果有值
        
        manager.drivingDistance = [drivingInfo[DrivingDistanceKey] doubleValue];
        
        // 行驶过的点
        NSArray *drivingCoordinates = drivingInfo[RouteCoordinatesKey];
        if (drivingCoordinates && drivingCoordinates.count > 0) { // 如果记录的有行驶过的点
            
            for (NSDictionary *coordinateDictionary in drivingCoordinates) {
                
                double latitude = [coordinateDictionary[LatitudeKey] doubleValue];
                double longitude = [coordinateDictionary[LongitudeKey] doubleValue];
                
                if (latitude != 0 && longitude != 0) {
                    CLLocationCoordinate2D coordinate2D = CLLocationCoordinate2DMake(latitude, longitude);
                    [manager.routeCoordinates addObject:[NSValue valueWithMACoordinate:coordinate2D]];
                }
            }
        }
    }
    
    

    return manager;
}


/**
 添加位置点

 @param coordinate 位置
 */
- (void)add:(CLLocationCoordinate2D)coordinate {
    
    if (coordinate.latitude == 0 || coordinate.longitude == 0) { // 如果定位失败不添加
        
        return;
    }
    // 计算与上一个位置点的距离
    NSValue *tmpValue = self.routeCoordinates.lastObject;
    double distance = 0.0;
    if (tmpValue) {
        
        if (self.currentMapType == MapTypeGD) {
            
            distance = [MapGeometryCalculationManager calculateTheDistanceBetweenStartMAMapPoint:[tmpValue MACoordinateValue] endMAMapPoint:coordinate];
        }else {
            
            CLLocationCoordinate2D lastLocation = [tmpValue MKCoordinateValue];
            CLLocation *lastL = [[CLLocation alloc] initWithLatitude:lastLocation.latitude longitude:lastLocation.longitude];
            distance = [lastL distanceFromLocation:[[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude]];
        }
        
    }
    else {
        
        distance = 0.0;
    }
    
    // 如果距离小于100米不执行，因为定位点可能会飘
    if (distance < 30 && self.routeCoordinates.count != 0) {
        return;
    }
    // 判断是否轨迹纠偏中
    if (self.isProgressing) {
        self.tempDistance += distance;
    }else {
        if (distance < 300) {
            self.drivingDistance += distance;
        }
    }
    
    // 保存点
    [self.routeCoordinates addObject:[NSValue valueWithMKCoordinate:coordinate]];

    
    
    
    // 保存数据
    [self save];
    
    // 是否需要轨迹纠偏，并且与上一个点的距离大于500米
    if (self.isLost || distance >= 300) {
        // 轨迹纠偏
        
        if ([MapManager shareManager].currentMapType == MapTypeGD) {
            
            [self trackCorrection];
        }
        
    }
    
}


/**
 轨迹纠偏计算,获取最新的行驶距离
 */
- (void)trackCorrection {
    
    if (self.routeCoordinates.count <= 0) {
        
        return;
    }
    
    if (self.operation != nil) { // 如果进程不为空,正在轨迹纠偏计算
        
        [self.operation cancel]; // 取消进程
    }
    
    self.isProgressing = YES;
    self.isLost = NO;
    
    NSMutableArray <MATraceLocation *>*traceItems = [NSMutableArray array]; // 参与计算的位置点集合
    NSInteger index = 0;
    NSInteger step = 1; // 获取参与计算位置点的步幅
    if (self.routeCoordinates.count > 1000) { // 如果记录的点数大于1000,那么提高位置记录点的步幅
        
        step = (NSInteger)ceil(self.routeCoordinates.count / 1000.0);
    }
    
    // 抽取本地缓存的该订单的运动轨迹点的集合中的位置点(如果缓存的有),添加到参与计算的集合中
    // 遍历所有的位置点集合,并根据步幅取出需要参与计算的位置点
    while (index < self.routeCoordinates.count - 1) {
        
        MATraceLocation *item = [[MATraceLocation alloc] init];
        item.loc = [self.routeCoordinates[index] MACoordinateValue];
        [traceItems addObject:item];
        index += step; // 如果司机位置轨迹点大于大于1000, step不在为1,也就是我们计算轨迹的集合不是所有的点都参与轨迹纠偏的计算,而是我们保存的位置点根据步幅跳跃添加,如果保存的位置点小于1000,参与计算的位置点集合是所有点, 如果大与1000,参与计算点的集合分别为第0 , step , 2 * step ... n * step < (self.routeCoordinates.count - 1);
    }
    
    // 最后一个点必须添加,不管 traceItems 是否包含这个点,包含了也没有太大影响,因为两个相同的点计算的结果并没什么影响
    MATraceLocation *lastItem = [[MATraceLocation alloc] init];
    lastItem.loc = [self.routeCoordinates.lastObject MACoordinateValue];
    [traceItems addObject:lastItem];
    
    MATraceManager *manager = [MATraceManager new];
    self.operation = [manager queryProcessedTraceWith:traceItems type:(AMapCoordinateTypeGPS) processingCallback:^(int index, NSArray<MATracePoint *> *points) {
        
    } finishCallback:^(NSArray<MATracePoint *> *points, double distance) {
        
        // 如果计算后的距离大于我们缓存的距离,这里刷新缓存距离
        if (distance > self.drivingDistance) {
            
            self.drivingDistance = distance;
        }
        
        // 轨迹纠偏计算完毕
        self.isProgressing = NO;
        // 如果轨迹纠偏计算的时间较长,那么在这段时间,我们扔会在持续的计算距离,这个距离是我们每次跟新位置点(最新点)都会与缓存的最后一个位置点(上一个点)计算得到最新的距离,刷新缓存的距离 drivingDistance,缓存距离与本地存储的距离不一样,缓存会因为app特殊的状况清空,但是本地存储的不会
        self.drivingDistance += self.tempDistance;
        // 置0缓存的位置距离
        self.tempDistance = 0;
        
    } failedCallback:^(int errorCode, NSString *errorDesc) {
        
        self.isLost = YES; // 计算失败需要我们从新计算距离
    }];
}


/**
 获取最新的总行驶距离

 @return 最新的总的行驶距离 单位: 米
 */
- (double)getTheLastTotalDistance {
    
    
    return self.drivingDistance;
}


/**
 获取最近两点的距离,单位: 米

 @return 返回最近两点的距离
 */
- (double)getThelastedDistance {
    
    return self.lastedDistance;
}


/**
 保存数据
 */
- (void)save {
    
    NSMutableDictionary *driverInfo = [NSMutableDictionary dictionary];
    driverInfo[DrivingDistanceKey] = @(self.drivingDistance);
    
    // 司机行驶过的位置点集合
    NSMutableArray *drivingCoordinates = [NSMutableArray array];
    
    for (NSValue *tempValue in self.routeCoordinates) {
        
        CLLocationCoordinate2D tempCoordinate2d = [tempValue MACoordinateValue];
        [drivingCoordinates addObject:@{LatitudeKey : @(tempCoordinate2d.latitude) , LongitudeKey : @(tempCoordinate2d.longitude)}];
    }
    
    driverInfo[RouteCoordinatesKey] = drivingCoordinates;
    
    if (self.orderId) {
        
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:driverInfo options:NSJSONWritingPrettyPrinted error:nil];

        
        [[NSUserDefaults standardUserDefaults] setValue:jsonData forKey:[NSString stringWithFormat:@"%@_%@" , self.orderId , DrivingInfoKey]];
        
    }
}

/// 清除缓存
- (void)cleanCache {
    
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:@"%@_%@" , self.orderId , DrivingInfoKey]];
    self.lastedDistance = 0.0;
    self.drivingDistance= 0.0;
    self.tempDistance = 0.0;
    self.isLost = YES;
    [self.routeCoordinates removeAllObjects];
}

- (void)dealloc {
    
    NSLog(@"里程计算销毁了");
}

@end
